//
//  FMDBOperation.m
//  高仿暴走斗图
//
//  Created by key on 16/10/11.
//  Copyright © 2016年 huangsongyao. All rights reserved.
//

#import "FMDBOperation.h"
#import "FMResultSet+Model.h"

@interface FMDBOperation ()

@property (nonatomic, strong) NSMutableArray <HSYFMDBOperationInfo *>*databaseTables;

@end

@implementation FMDBOperation

- (instancetype)initWithDatabaseTables:(NSMutableArray <HSYFMDBOperationInfo *>*)tables {
    
    if (self = [super init]) {
        _databaseTables = tables;                               //数据表名，集合
        [self initDB];
    }
    return self;
}

#pragma mark - Init DataBase

- (void)initDB {
    
    _dateBase = [FMDBOperation inits];                          //创建数据库
    _dateBasePath = [FMDBOperation dataBasePath];               //数据库路径
    self.dateBase.traceExecution = YES;                         //跟踪执行
    if ([self.dateBase open]) {
        for (HSYFMDBOperationInfo *operation in self.databaseTables) {
            BOOL isExist = [self.dateBase tableExists:operation.name];
            if (isExist) {
                NSLog(@"%@ existing", operation.name);
            } else {
                BOOL result = [self.dateBase executeUpdateWithFormat:[NSString stringWithFormat:@"CREATE TABLE %@ (%@)", operation.name, [operation toDataBaseTableField]], nil];
                if (result) {
                    NSLog(@"%@ create successful", operation.name);
                } else {
                    NSLog(@"%@ create failure", operation.name);
                }
            }
        }
        [self.dateBase close];                                  //关闭数据库
    } else {
        NSLog(@"FMDB open failure");
    }
}

- (void)fmdb_operationForExecuteUpdateBlock:(id(^)())block completed:(void(^)(id x))completed
{
    if (![self.dateBase open]) {
        return;
    }
    id result = nil;
    if(block) {
        result = block();
    }
    [self.dateBase close];
    if (result && completed) {
        completed(result);
    }
}

//********************************************数据库操作*************************************************//

#pragma mark - Insert Data

- (void)fmdb_insertDataForOperationInfo:(HSYFMDBOperationInfo *)operationInfo completed:(void(^)(BOOL result))completed {
    
    @weakify(self);
    [self fmdb_operationForExecuteUpdateBlock:^{
        @strongify(self);
        BOOL result = [self fmdb_insertDataForOperationInfo:operationInfo];
        return @(result);
    } completed:^(id x){
        if (completed) {
            completed([x boolValue]);
        }
    }];
}

- (void)fmdb_beginTransactionInsertDataForOperationInfos:(NSMutableArray <HSYFMDBOperationInfo *>*)operationInfos completed:(void(^)(BOOL result))completed {
    
    if (![self.dateBase open]) {
        return;
    }
    [self.dateBase beginTransaction];
    BOOL isRollBack = NO;
    @try {
        for (HSYFMDBOperationInfo *operationInfo in operationInfos) {
            BOOL result = [self fmdb_insertDataForOperationInfo:operationInfo];
            if (completed && !result) {
                completed(result);
            }
        }
    }
    @catch (NSException *exception) {
        isRollBack = YES;
        [self.dateBase rollback];
    }
    @finally {
        if (!isRollBack) {
            [self.dateBase commit];
        }
    }
    [self.dateBase close];
}

- (BOOL)fmdb_insertDataForOperationInfo:(HSYFMDBOperationInfo *)operationInfo {

    BOOL result = NO;
    result = [self.dateBase executeUpdateWithFormat:[NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (%@)", operationInfo.name, [operationInfo toDataBaseTableInsertFields], [operationInfo toDataBaseTableInsertStatements]], nil];
    if (!result) {
        NSLog(@"Insert %@ Failure!", [operationInfo toDataBaseTableInsertStatements]);
    } 
    return result;
}

#pragma mark - Query Data

- (void)fmdb_queryAllDataForOperationInfo:(HSYFMDBOperationInfo *)operationInfo completed:(void(^)(NSMutableArray *result))completed {
    @weakify(self);
    [self fmdb_operationForExecuteUpdateBlock:^{
        @strongify(self);
        NSMutableArray *contentArray = [[NSMutableArray alloc] init];
        FMResultSet *resultSet = [self.dateBase executeQueryWithFormat:[NSString stringWithFormat:@"SELECT * FROM %@", operationInfo.name], nil];
        while ([resultSet next]) {
            NSMutableDictionary *result = [resultSet fmdbForColumn:operationInfo];
            [contentArray addObject:result];
        }
        return contentArray;
    } completed:^(NSMutableArray *result){
        if(completed) {
            completed(result);
        }
    }];
}

- (void)fmdb_queryDataForOperationInfo:(HSYFMDBOperationInfo *)operationInfo whereField:(NSString *)field whereContent:(NSString *)content completed:(void(^)(NSMutableArray *result))completed {
    @weakify(self);
    [self fmdb_operationForExecuteUpdateBlock:^{
        @strongify(self);
        NSMutableArray *contentArray = [[NSMutableArray alloc] init];
        FMResultSet *resultSet = [self.dateBase executeQueryWithFormat:[NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@ = '%@'", operationInfo.name, field, content], nil];
        while ([resultSet next]) {
            NSMutableDictionary *result = [resultSet fmdbForColumn:operationInfo];
            [contentArray addObject:result];
        }
        return contentArray;
    } completed:^(NSMutableArray *result){
        if(completed) {
            completed(result);
        }
    }];
}

#pragma mark - Delete Data

- (void)fmdb_deleteRowDataForTableName:(NSString *)tableName deleteValue:(NSString *)value whereField:(NSString *)field completed:(void(^)(BOOL result))completed {
    @weakify(self);
    [self fmdb_operationForExecuteUpdateBlock:^id{
        @strongify(self);
        BOOL result = [self.dateBase executeUpdateWithFormat:[NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = '%@'", tableName, field, value], nil];
        if (!result) {
            NSLog(@"delete %@ = %@ failure", field, value);
        }
        return @(result);
    } completed:^(id x) {
        if (completed) {
            completed([x boolValue]);
        }
    }];
}

#pragma mark - Modify Data

- (void)fmdb_modifyDataForTableName:(NSString *)tableName updateField:(NSString *)updateField updateContent:(NSString *)updateContent whereField:(NSString *)whereField whereContent:(NSString *)whereContent completed:(void(^)(BOOL result))completed {
    @weakify(self);
    [self fmdb_operationForExecuteUpdateBlock:^id{
        @strongify(self);
        BOOL result = [self.dateBase executeUpdateWithFormat:[NSString stringWithFormat:@"UPDATE %@ SET %@ = '%@' WHERE %@ = '%@'", tableName, updateField, updateContent, whereField, whereContent], nil];
        if (!result) {
            NSLog(@"Update %@ Set %@ = %@ failure", tableName, updateField, updateContent);
        } 
        return @(result);
        
    } completed:^(id x) {
        if (completed) {
            completed([x boolValue]);
        }
    }];
}

#pragma mark - Clean Table

- (void)fmdb_clearDataToTableName:(NSString *)tableName completed:(void(^)(BOOL result))completed {
    @weakify(self);
    [self fmdb_operationForExecuteUpdateBlock:^id{
        @strongify(self);
        BOOL result =[self.dateBase executeUpdateWithFormat:[NSString stringWithFormat:@"DELETE FROM %@", tableName], nil];
        if (!result) {
            NSLog(@"clear %@ failure", tableName);
        }
        return @(result);
    } completed:^(id x) {
        if (completed) {
            completed([x boolValue]);
        }
    }];
}

//***********************************************创建数据库**********************************************//

#pragma mark - Create DataBase

+ (FMDatabase *)inits {
    
    NSString *databasePath = [FMDBOperation dataBasePath];
    //创建数据库
    FMDatabase *db = [[FMDatabase alloc] initWithPath:databasePath];
    return db;
}

//**********************************************数据库缓存路径*******************************************//

#pragma mark - SQL Path

+ (NSString *)applicationDocumentsDirectory {
    
    return kPATH_DOCUMENT;
}

+ (NSString *)userDocumentsDirectory {
    
    return [FMDBOperation applicationDocumentsDirectory];
}

+ (NSString *)dataBasePath {
    
    NSString *databasePath =  [FMDBOperation userDocumentsDirectory];
    databasePath = [databasePath stringByAppendingPathComponent:kFMDB_DATABASE_FILE_NAME];
    
    
    return databasePath;
}

@end
